package com.apobates.forum.toro.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Constructor;
import java.util.*;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class CommonHelper {
    private final static Logger logger = LoggerFactory.getLogger(CommonHelper.class);
    /**
     * 首字母小写
     *
     * @param str
     * @return
     */
    public static String lowerFirstCase(String str){
        char[] chars = str.toCharArray();
        //首字母小写方法，大写会变成小写，如果小写首字母会消失
        chars[0] +=32;
        return String.valueOf(chars);
    }

    /**
     * 首字母大写
     *
     * @param str
     * @return
     */
    public static String upperFirstCase(String str) {
        char[] chars = str.toCharArray();
        //首字母小写方法，大写会变成小写，如果小写首字母会消失
        chars[0] -= 32;
        return String.valueOf(chars);
    }

    /**
     * 从集合中找出指定属性等于期待的值的元素,使用BullBeanHelper.isSameObj来进行目标是否一致判断
     *
     * @param result 搜索的集合
     * @param findAttrName 搜索的属性名(id)
     * @param findAttrType 搜索的属性类型名(long)
     * @param expectVal 属性期待的值,只支持: 基本类型/包装类和字符串
     * @return
     */
    public static <T> Optional<T> seekFirstEle(Collection<T> result, String findAttrName, String findAttrType, Object expectVal) {
        if(null == expectVal){
            return Optional.empty();
        }
        Predicate<T> filterFun = (obj)-> {
            Object seekJoinVal = null;
            try {
                seekJoinVal = BeanHelper.getAttrVal(obj, findAttrName, findAttrType);
            }catch (Exception e){
                logger.debug("[CH][seekEle][First]seek element fail by Type,error:"+e.getMessage());
            }
            return (null == seekJoinVal)?false:BullBeanHelper.isSameObj(seekJoinVal, expectVal);
        };
        return result.stream().filter(filterFun).findFirst();
    }

    /**
     * 搜索第一个满足条件的元素后停止搜索,使用BullBeanHelper.isSameObj来进行目标是否一致判断
     *
     * @param result 搜索的集合
     * @param findAttrName 搜索的属性名(id)
     * @param expectVal 属性期待的值,只支持: 基本类型/包装类和字符串
     * @return
     */
    public static <T> Optional<T> seekFirstEle(Collection<T> result, String findAttrName, Object expectVal) {
        if(null == expectVal){
            return Optional.empty();
        }
        Predicate<T> filterFun = (obj)-> {
            Object seekJoinVal = null;
            try {
                seekJoinVal = BeanHelper.getAttrVal(obj, findAttrName);
            }catch (Exception e){
                logger.debug("[CH][seekEle][First]seek element fail,error:"+e.getMessage());
            }
            return (null == seekJoinVal)?false:BullBeanHelper.isSameObj(seekJoinVal, expectVal);
        };
        return result.stream().filter(filterFun).findFirst();
    }

    /**
     * 搜索所有满足条件的元素,使用BullBeanHelper.isSameObj来进行目标是否一致判断
     *
     * @param result 搜索的集合
     * @param findAttrName 搜索的属性名(id)
     * @param expectVal 属性期待的值,只支持: 基本类型/包装类和字符串
     * @return 返回一个List，若不满足条件或查找失败返回空列表
     * @param <T> 元素的类型
     */
    public static <T> Collection<T> seekAnyEle(Collection<T> result, String findAttrName, Object expectVal) {
        if(null == expectVal){
            return Collections.emptyList();
        }
        Predicate<T> filterFun = (obj)-> {
            Object seekJoinVal = null;
            try {
                seekJoinVal = BeanHelper.getAttrVal(obj, findAttrName);
            }catch (Exception e){
                logger.debug("[CH][seekEle][ListAny]seek element fail,error:"+e.getMessage());
            }
            return (null == seekJoinVal)?false:BullBeanHelper.isSameObj(seekJoinVal, expectVal);
        };
        return result.stream().filter(filterFun).collect(Collectors.toList());
    }

    /**
     * 搜索所有满足条件的元素,使用BullBeanHelper.isSameObj来进行目标是否一致判断
     *
     * @param result 搜索的集合
     * @param findAttrName 搜索的属性名(id)
     * @param expectVal 属性期待的值,只支持: 基本类型/包装类和字符串
     * @param collectionFactory 结果类型的供应函数
     * @return 返回供应函数指定的特定集合类型，若不满足条件或查找失败返回特定集合类型的实例(无数据)
     * @param <T> 元素的类型
     * @param <C> 结果类型，其必须是Colleciton的子类
     */
    public static <T,C extends Collection<T>> C seekAnyEle(Collection<T> result, String findAttrName, Object expectVal, Supplier<C> collectionFactory) {
        if(null == expectVal){
            return collectionFactory.get();
        }
        Predicate<T> filterFun = (obj)-> {
            Object seekJoinVal = null;
            try {
                seekJoinVal = BeanHelper.getAttrVal(obj, findAttrName);
            }catch (Exception e){
                logger.debug("[CH][seekEle][SupplierAny]seek element fail,error:"+e.getMessage());
            }
            return (null == seekJoinVal)?false:BullBeanHelper.isSameObj(seekJoinVal, expectVal);
        };
        return result.stream().filter(filterFun).collect(Collectors.toCollection(collectionFactory));
    }

    /**
     * 搜索所有满足条件的元素,使用BullBeanHelper.isSameObj来进行目标是否一致判断
     * 搜索的实现委托: seekAnyEle(Collection<T>, String, Object) 来实现。最后只根据Class来对计算结果进行转换(通过构造函数(Collection))
     *
     * @param target 搜索的集合
     * @param findAttrName 搜索的属性名(id)
     * @param expectVal 属性期待的值,只支持: 基本类型/包装类和字符串
     * @param resultType 结果类型的Class实例
     * @return 返回指定的特定集合类型，若不满足条件或查找失败返回null
     * @param <T> 元素的类型
     */
    public static <T> Collection seekAnyEle(Collection<T> target, String findAttrName, Object expectVal, Class resultType) {
        Collection<T> tmp = seekAnyEle(target, findAttrName, expectVal);
        try {
            Constructor declaredConstructor = resultType.getDeclaredConstructor(Collection.class);
            Object o = declaredConstructor.newInstance(tmp);
            return (Collection) o;
        }catch (Exception e){
            String ccc = "[CH][seekEle][ClassAny]seek element fail,error:"+e.getMessage();
            logger.debug(ccc);
        }
        return null;
    }

    /**
     * 使用StringTokenizer来分解单词
     *
     * @param strVal 目标字符串
     * @param delimiters 分隔符
     * @return
     */
    public static List<String> matchWordByToken(String strVal, String delimiters) {
        List<String> words = new ArrayList<>();
        StringTokenizer st = new StringTokenizer(strVal, delimiters);
        while(st.hasMoreElements()){
            words.add(st.nextToken());
        }
        return words;
    }

    /**
     * 提取所有英文单词
     *
     * @param strVal 目标字符串
     * @return
     */
    public static List<String> matchWordByReg(String strVal) {
        String regex = "[a-zA-Z]+";
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(strVal);
        List<String> words = new ArrayList<>();
        while (m.find()) {
            words.add(m.group());
        }
        return words;
    }

    /**
     * 提取指定格式的英文单词
     *
     * @param regex 正则表达式字符串
     * @param strSource 目标字符串
     * @return
     */
    public static List<String> regExtract(String regex, String strSource) {
        // String regEx = "(.*)=select\\((.*):(.*)\\)";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(strSource);
        int matchSize = matcher.groupCount();
        if (matchSize == 0) {
            return Collections.emptyList();
        }
        List<String> words = new ArrayList<>();
        while(matcher.find()) {
            for (int index = 0; index <= matchSize; index++) {
                if (matcher.group(index).equals(strSource)) {
                    continue;
                }
                words.add(matcher.group(index));
            }
        }
        return words;
    }

    /**
     * 获取目标字符串中所有查找字符所在的下标
     * @param target 目标字符串
     * @param findStr 子字符串
     * @return 字符串在母字符串中下标集合，如果母字符串中不包含子字符串，集合长度为零
     */
    public static List<Integer> getIndex(String target, String findStr){
        List<Integer> list=new ArrayList<>();
        int index = target.indexOf(findStr);
        while (index != -1) {
            list.add(index);
            index = target.indexOf(findStr, index + findStr.length());
        }
        return list;
    }
    /**
     * 查看下标最接近的元素，基于目标列表中元素的接近
     * @param referEle 参考的元素
     * @param targetList 查找的目标元素集合
     * @param isLess true第一个小于参考元素,false第一个大于参考元素
     * @return
     */
    public static Integer getReferElement(Integer referEle, List<Integer> targetList, boolean isLess){
        List<Integer> tmp = new ArrayList<>(targetList);
        Collections.sort(tmp);
        Integer rs = null;
        for(Integer ele : tmp){
            if (isLess && ele.compareTo(referEle) == -1){
                rs = ele;
            }
            if (!isLess && ele.compareTo(referEle) == 1 && rs == null){
                rs = ele;
            }
        }
        return rs;
    }

    public static String toString(List<Integer> rs, String seplitor){
        return rs.stream().map(String::valueOf).collect(Collectors.joining(seplitor));
    }
}
